import * as three from "three";
import { Mesh, Sprite } from "three";
import { MyAtlas } from "./atlas";


//==========套路部分，这个部分的代码基本不用管
var render: three.WebGLRenderer;
var camera: three.OrthographicCamera;
var scene: three.Scene;

var textureLoader: three.TextureLoader;

var atlas: MyAtlas.Atlas;
var logo: three.Mesh;
window.onload = () => {
    //threejs基本组件的初始化，这是个固定过程，一开始不需要理解，照着抄就行
    render = new three.WebGLRenderer();//渲染器
    render.setClearColor(0xff80ff);//背景色

    //摄像机，2d只需要用正交投影，这里只做个基本的初始化
    camera = new three.OrthographicCamera(-100, 100, 100, -100);
    camera.position.set(0, 0, 10);
    camera.lookAt(0, 0, 0);

    //场景
    scene = new three.Scene();

    //贴图加载模块
    textureLoader = new three.TextureLoader();

    onInit();

    //开始主循环
    looper();


};

function looper(): void {
    onUpdate();

    render.render(scene, camera);

    requestAnimationFrame(looper);
}

var screenheight: number = 0;
var screenwidth: number = 0;
var planeheight: number = 0;
function setSize(w: number, h: number): void {
    render.setSize(w, h);


    var asp = w / h;
    //适配思路，宽度固定200；
    screenwidth = 200;
    screenheight = screenwidth / asp;

    screenwidth = 200;
    //camera的高度可以点对点
    //camera.bottom = -h / 2;
    //camera.top = h / 2;
    camera.bottom = screenheight * -0.5;
    camera.top = screenheight * 0.5;
    //也可以不点对点

    camera.left = screenwidth * -0.5;
    camera.right = screenwidth * 0.5;
    camera.updateProjectionMatrix();
}

//====逻辑部分
var back: three.Mesh;
function onInit() {
    //render会创建一个canvas，下面是控制他的尺寸



    //放进我们指定的区域
    var _div = document.getElementById("threejswin") as HTMLDivElement;
    _div.appendChild(render.domElement);
    //size
    setSize(_div.clientWidth, _div.clientHeight);
    window.addEventListener("resize", () => {
        setSize(_div.clientWidth, _div.clientHeight);
    });

    _div.addEventListener("mousemove", (ev: MouseEvent) => {
        //threejs 射线相机计算用的投影空间
        //要把鼠标换算回这个空间 ，左-1，右1，下-1，上1
        onmouseover(ev.offsetX / _div.clientWidth * 2 - 1, -1 * (ev.offsetY / _div.clientHeight * 2 - 1));
    })
    //加载贴图，初始化材质

    //这个tex是异步加载的，所以其实一开始会画不出来，过几帧加载出来才能显示，一开始无须处理这些细节


    //因为atals要加载一个json，我们等一下继续初始化
    atlas = new MyAtlas.Atlas(textureLoader, "imgs/cat.json", "imgs/cat.png", 2.5, onatalsloaded);


    //因为我们的画布单位宽度为200，所以一个200的plane 永远横向撑满整个画布
    planeheight = 200 / 3.25 * 5.25;


    //搞个背景
    {
        var texback = textureLoader.load("imgs/back.jpg");
        var plane = new three.PlaneGeometry(200, planeheight);
        var uv = plane.getAttribute("uv");

        back = new three.Mesh(plane, new three.MeshBasicMaterial(
            { map: texback }
        ));
        back.name = "back";
    }
    //默认相机是从 10 看向0 ， 所以大于9.9就没了,离相机太近看不见
    //数字越小越在地下，数字越大越在上面
    //< -1990 也没了，离相机太远也看不见
    var z = -0.1;
    back.position.set(0, 0, z);
    scene.add(back);

    {
        var texlogo = textureLoader.load("imgs/md.png");

        //因为要搞出锚点效果，这里的模型尺寸没有意义了
        var logoplane = new three.PlaneGeometry(1, 1);
        var pos = logoplane.getAttribute("position");
        //以 0,0,0 为中点，重新设定四个角
        pos.setXYZ(0, -50, 0, 0);//左上角
        pos.setXYZ(1, 50, 0, 0);//右上角
        pos.setXYZ(2, -50, -100, 0)//左下角
        pos.setXYZ(3, 50, -100, 0)//右下角
        logo = new three.Mesh(logoplane, new three.MeshBasicMaterial(
            { map: texlogo, transparent: true }
        ));
        logo.position.set(0, 0, 0);
        scene.add(logo);
        logo.name = "logo";
    }
}
var cats: Mesh[] = [];
function onmouseover(x: number, y: number) {


    var rc = new three.Raycaster();
    rc.setFromCamera({ x, y }, camera);


    //把所有猫的颜色正常化
    for (var i = 0; i < cats.length; i++) {
        (cats[i].material as three.MeshBasicMaterial).color.set(0xffffffff);
    }
    //直接检查全场景
    //var result = rc.intersectObjects(scene.children, true);

    //尽量不要查全场景，只检查自己准备的列表
    var result = rc.intersectObjects(cats, true);

    //如果碰到了啥玩意儿就把他改成红色
    if (result.length > 0) {
        var last = result[result.length - 1].object as Mesh;
        if (last != null) {

            (last.material as three.MeshBasicMaterial).color.set(0xffff0000);//aRGB
        }
        //console.log("result=" + result[result.length-1].object.name);
    }

}
function onatalsloaded(at: MyAtlas.Atlas) {
    var cat1 = at.CreatePlaneMesh("cat01");
    cat1.position.set(-50, 50, 0);
    cat1.name = "cat1";
    scene.add(cat1);

    var cat2 = at.CreatePlaneMesh("cat02");
    cat2.position.set(0, 50, 0);
    cat2.name = "cat2";
    scene.add(cat2);

    var cat3 = at.CreatePlaneMesh("cat03");
    cat3.position.set(50, -50, 0);
    cat3.name = "cat3";
    scene.add(cat3);


    cats.push(cat1);

    cats.push(cat2);

    cats.push(cat3);

    var ani = new MyAtlas.AniObj(at);
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat01"), 0.1));
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat02"), 0.1));
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat03"), 0.1));
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat04"), 0.1));
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat05"), 0.1));
    ani.frames.push(new MyAtlas.Frameinfo(at.GetSpriteMesh("cat06"), 0.1));
    scene.add(ani);

    cats.push(ani);
}
var timer = 0;
function onUpdate() {
    back.position.set(0, (screenheight - planeheight) * 0.5, 0);
    timer += 0.016;
    if (timer > 2.0) {
        timer = 0;
    }
    if (timer > 1.0) {
        logo.setRotationFromAxisAngle(new three.Vector3(0, 0, 1), (2.0 - timer) - 0.5);
    }
    else {
        logo.setRotationFromAxisAngle(new three.Vector3(0, 0, 1), timer - 0.5);
    }

}